/*
 * Copyright (c) Jan Šlahora (${USER}) - 2012.
 * Created in IntelliJ IDEA 10.5
 */

package GUIComponents.AgregaceComponents;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;

/*
*   File AgregaceGraf 
*   in package GUIComponents.AgregaceComponents
*   was created by slaha
*   on 20.3.12 at 16:12.
*
*/
public class AgregaceGraf extends JPanel implements MouseMotionListener {

  final short SPODNI_OKRAJ = 35;
  final short LEVY_OKRAJ = 35;
  private int w;
  private int h;
  ArrayList<Double> prumery;
  ArrayList<Double> teorie;
  int[] bodyX;
  double max;
  double min;
  int minY;
  int maxY;
  JLabel label;
  JTable t;

  ArrayList<Point> prumeryBody;
  ArrayList<Point> teorieBody;

  AgregaceGraf(ArrayList<Double> prumery, ArrayList<Double> teorie, JLabel label, JTable t) {
    addMouseMotionListener(this);
    this.prumery = prumery;
    this.teorie = teorie;
    bodyX = new int[prumery.size()];
    this.label = label;
    this.t = t;
  }

  private ArrayList<Point> dejBody(ArrayList<Double> hodnoty) {
    ArrayList<Point> al = new ArrayList<>();

    double rozdil = max - min;
    int delka = minY - maxY;
    double pxProJeden = delka / rozdil;
    for (int i = 0; i < hodnoty.size(); i++) {
      int x = bodyX[i];
      double hodnota = hodnoty.get(i) - min;
      int y = (int) (minY -  Math.round(hodnota * pxProJeden));

      Point p = new Point(x, y);

      al.add(p);
    }

    return  al;
  }
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;
 //   g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
 //       RenderingHints.VALUE_ANTIALIAS_ON);
    w = getWidth();
    h = getHeight();
    g2.setPaintMode();
    setBackground(Color.WHITE);
    setForeground(Color.BLACK);
    // Y
    Line2D y = new Line2D.Double(LEVY_OKRAJ, LEVY_OKRAJ, SPODNI_OKRAJ, h - SPODNI_OKRAJ);
    g2.draw(y);
    //PAD, PAD, PAD, h - PAD
    // Draw X
    Line2D x = new Line2D.Double(LEVY_OKRAJ, h - SPODNI_OKRAJ, w - LEVY_OKRAJ, h - SPODNI_OKRAJ);
    g2.draw(x);

    vykresliPopiskyX(g2, x);
    vykresliPopiskyY(g2, y);

    this.teorieBody = dejBody(teorie);
    this.prumeryBody = dejBody(prumery);

    g2.setStroke(new BasicStroke(2f));
    vykresliPrimky(g2);
    vykresliBody(g2);
  }

  private void  vykresliBody(Graphics2D g) {
    for (Point p : prumeryBody) {
      g.drawRect(p.x-3, p.y-3, 6, 6);
    }
  }

  private void vykresliPrimky(Graphics2D g) {
    Point predchozi = teorieBody.get(0);
    for (Point p : teorieBody) {
      g.drawLine(predchozi.x, predchozi.y, p.x, p.y);
      predchozi = p;
    }
  }

  private void vykresliPopiskyX(Graphics2D g, Line2D primka) {
    g.setStroke(new BasicStroke(1));
    double delka =(Math.abs(primka.getX2() - primka.getX1()));
    double rozestup = (delka / (prumery.size()-1));
    int y = h - SPODNI_OKRAJ + 15;

    FontMetrics metrics = new FontMetrics(new Font("Verdana", Font.PLAIN, 10)) {
    };
    
    for (int i = 0; i < prumery.size(); i++ ) {
      String label = Integer.toString(i+1);

      int x = (int) Math.round(LEVY_OKRAJ + (i * rozestup));
      bodyX[i] = x;

      Rectangle2D bounds = metrics.getStringBounds(label, null);
      int widthInPixels = (int) bounds.getWidth();

      g.drawLine(x, h - SPODNI_OKRAJ - 2, x, h - SPODNI_OKRAJ + 2);
      g.drawString(label, (int) (x - (0.5*widthInPixels)), y);
    }
  }

  private void vykresliPopiskyY(Graphics2D g, Line2D primka) {
    g.setStroke(new BasicStroke(1));
    min = dejMinimum();
    max = dejMaximum();

    max = Math.ceil(max) + 1;
    min = Math.floor(min) - 1;

    int x = LEVY_OKRAJ - 30;

    double delka = (Math.abs(primka.getY2() - primka.getY1()));
    double rozestup =  (delka / (max + Math.abs(min)));

    FontMetrics metrics = new FontMetrics(new Font("Verdana", Font.PLAIN, 10)) {
    };

    double prirustek;

    if (rozestup > 30) {
      prirustek = 0.5;
    } else if (rozestup < 10) {
      prirustek = 5;
    } else {
      prirustek = 1;
    }

    double lokalMin = min;
    for (double i = 0; lokalMin <= max; lokalMin+=prirustek) {
      String label = Double.toString(lokalMin);

      int y = (int) Math.round(h - SPODNI_OKRAJ - (i * rozestup));
      if (i == 0) {
        minY = y;
      } else {
        maxY = y;
      }
      
      i+=prirustek;
      
      Rectangle2D bounds = metrics.getStringBounds(label, null);
      int heightInPixels = (int) bounds.getHeight();

      g.drawLine(LEVY_OKRAJ - 2, y, LEVY_OKRAJ + 2, y);
    
      g.drawString(label, x, (int) (y + (0.5 * heightInPixels)));
    }
  }

  private double  dejMinimum() {
    double m = prumery.get(0);

    for (double d : prumery) {
      if (d < m) {
        m = d;
      }
    }
    for (double d : teorie) {
      if (d < m) {
        m = d;
      }
    }
    return m;
  }

  private double dejMaximum() {
    double m = prumery.get(0);

    for (double d : prumery) {
      if (d > m) {
        m = d;
      }
    }
    for (double d : teorie) {
      if (d > m) {
        m = d;
      }
    }
    return m;
  }

  @Override
  public void mouseDragged(MouseEvent e) {
    //To change body of implemented methods use File | Settings | File Templates.
  }

  /**
   * Invoked when the mouse cursor has been moved onto a component
   * but no buttons have been pushed.
   */
  @Override
  public void mouseMoved(MouseEvent e) {
    Point mys = e.getPoint();
    Point pPrum, pTeor;
    Graphics g = this.getGraphics();
    String str = "";
    int sloupec = -1;
    ((Graphics2D) g).setStroke(new BasicStroke(2f));

    for (int i = 0; i < prumeryBody.size(); i++) {
      pPrum = prumeryBody.get(i);
      pTeor = teorieBody.get(i);
      if ((((mys.x >= pPrum.x -2) && (mys.x <= pPrum.x + 2)) &&
          ((mys.y >= pPrum.y -2)&& (mys.y <= pPrum.y + 2))))
      {
        zvyrazneni(i, g);
        g.fillRect(pPrum.x-3, pPrum.y-3, 6, 6);

        break;

      } else if ((((mys.x >= pTeor.x - 2) && (mys.x <= pTeor.x + 2)) &&
                ((mys.y >= pTeor.y - 2) && (mys.y <= pTeor.y + 2))))
      {
        zvyrazneni(i, g);

        break;


      } else {
        Color c = g.getColor();
        g.setColor(this.getBackground());
        g.fillRect(pPrum.x - 3, pPrum.y - 3, 6, 6);
        g.fillRect(pTeor.x - 4, pTeor.y - 4, 8, 8);
        g.setColor(c);
        vykresliPrimky((Graphics2D) g);
        g.drawLine(LEVY_OKRAJ, LEVY_OKRAJ, SPODNI_OKRAJ, h - SPODNI_OKRAJ);
        t.clearSelection();
        label.setText("");
        vykresliBody((Graphics2D) g);
      }
    }

  }

  private void zvyrazneni(int i, Graphics g) {
    Point pPrum = prumeryBody.get(i);
    Point pTeor = teorieBody.get(i);
    g.fillRect(pPrum.x - 3, pPrum.y - 3, 6, 6);
    g.fillRect(pTeor.x - 4, pTeor.y - 4, 8, 8);
    label.setText("ØS = " + prumery.get(i) + "    Ŝ = " + teorie.get(i));
    t.setColumnSelectionInterval(i + 1, i +1);
  }
}
